
var WebViewModel = function (data) {
    var self = this;

    self.WebTitle = ko.observable();
    self.WebDescription = ko.observable();

    self.Lists = ko.mapping.fromJS([], {});
    self.Rows = ko.mapping.fromJS([], {});
    self.List = ko.observable(null);
    self.LoadingPercent = ko.observable(0);

    self.ListUITemplate = ko.computed(function () {
        if (self.List() == null) return "";
        return self.List().ListUITemplate();
    });

    self.GetLists = function () {
        // server relative url to REST service endpoint
        // var ajaxUrl = SP.Utilities.UrlBuilder.urlCombine(_spPageContextInfo.webServerRelativeUrl, "_vti_bin/listdata.svc/");

        var ctx = SP.ClientContext.get_current();
        var web = ctx.get_web();
        var listCollection = web.get_lists();
        ctx.load(web);
        ctx.load(listCollection, "Include(Id,Title,ImageUrl,Description,IsApplicationList,Hidden,BaseTemplate)");

        ctx.executeQueryAsync(
            Function.createDelegate(this,
                function () {

                    self.WebTitle(web.get_title());
                    self.WebDescription(web.get_description());

                    var lists = [];
                    for (var i = 0; i < listCollection.get_count(); i++) {
                        var l = listCollection.get_item(i);

                        if (l.get_hidden()) continue;

                        lists.push({
                            "Id": l.get_id(),
                            "Title": l.get_title(),
                            "Description": l.get_description(),
                            "ImageUrl": l.get_imageUrl(),
                            "BaseTemplate": l.get_baseTemplate()
                        });
                        // lists.sort(function (a,b) { return a.BaseTemplate > b.BaseTemplate; });
                    }

                    ko.mapping.fromJS(lists, listInfoMapping, self.Lists)
                }),
            Function.createDelegate(this,
                function (sender, args) {
                    alert(args.get_message());
                })
        );
    };

    self.GetList = function (list) {
        if (!list) return;
        var name = list.RestName();
        if (!name) return;

        var ajaxUrl = SP.Utilities.UrlBuilder.urlCombine(_spPageContextInfo.webServerRelativeUrl, "_vti_bin/listdata.svc/" + name + "/");
        self.List(list);

        ko.mapping.fromJS([], {}, self.Rows);
        self.LoadingPercent(0);
        $.ajax({
            type: "GET",
            url: ajaxUrl,
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            cache: false,
            processData: true,
            success: function (data, status, xhr) {
                if (status == "success" && data) {
                    try {
                        ko.mapping.fromJS(data.d.results, listItemMapping, self.Rows)
                    }
                    catch (ex) {
                        self.Rows = ko.mapping.fromJS([], {});
                    }
                }
                self.LoadingPercent(100);
            },
            error: function (xhr, status, message) {
                alert(message + name);
            }
        });
    };

    self.wookmark = function () {
        $('.image-list-template').css("width", $('#list-container').width());
        $('.image-list-template .hero-unit').wookmark({ offset: 15, container: $('.image-list-template') });
    };

};

var listInfoMapping = {
    //    'include': ["Title","Id","Description"],
    /*
    'key': function (data) {
        return ko.utils.unwrapObservable(data);
    },
    */
    'create': function (options) {
        return new ListInfoViewModel(options.data);
    }
};

var ListInfoViewModel = function (data) {
    var self = this;
    var $ = jQuery;

    self.Title = ko.observable("");
    self.Description = ko.observable("");
    self.BaseTemplate = ko.observable("");

    ko.mapping.fromJS(data, {}, this);

    self.RestName = ko.computed(function () {

        var url = ko.utils.unwrapObservable(self.Title);

        var r1 = /\b([a-z])/g;
        url = url.replace(r1, function (m, p) { return p.toUpperCase(); });

        var r2 = /\s/g;
        return url.replace(r2, "");
    });

    self.Active = ko.computed(function () {
        return self == vm.List();
    });

    self.ListUITemplate = ko.computed(function () {
        switch (self.BaseTemplate()) {
            case 851:
                return "image-list-template";
            default:
                return "list-template";
        }
    });

    self.ListIconClass = ko.computed(function () {
        var active = self.Active();
        var prefix = active ? "icon-white " : "";

        switch (self.BaseTemplate()) {
            case 101:
            case 851:
                return prefix + (active ? "icon-folder-open" : "icon-folder-close");
            default:
                break;
        }

        return prefix + "icon-th-list";
    });

    self.Select = function () {
        vm.GetList(self);
    };

};

var listItemMapping = {
    //    'include': ["Title","Id","Description"],
    /*
    'key': function (data) {
    return ko.utils.unwrapObservable(data.Id);
    },*/
    'create': function (options) {
        return new ListItemViewModel(options.data);
    }
};

var fieldMapping = {
    'key': function (data) {
        return ko.utils.unwrapObservable(data.Field);
    }
};

var ListItemViewModel = function (data) {
    var self = this;
    var r1 = /0x0101/g;
    var rd = new RegExp("Date\\([\\d+-]+\\)");

    self.Title = ko.observable("");
    self.Name = ko.observable("");
    self.ContentTypeID = ko.observable("");
    self.Mode = ko.observable("");

    self.IsDocumentLibrary = ko.computed(function () {
        return r1.test(self.ContentTypeID());
    });
    self.DisplayTitle = ko.computed(function () {
        // for document items - usually Name
        if (self.IsDocumentLibrary()) {
            return self.Name();
        }
        // for list items - usually Title
        return self.Title();
    });

    ko.mapping.fromJS(data, {}, this);

    self.Fields = ko.mapping.fromJS(
        $.map(data, function (v, f) {
            var t = typeof (v);
            var m = rd.exec(v);
            if (m) {
                v = eval("new " + m[0]);
                t = "date";
            }
            return { Field: f, Value: v, Type: t };
        }),
        fieldMapping);

    self.Expanded = ko.observable(false);

    self.Edit = function () {
        self.Mode("edit");
    };

    self.Editable = function (field) {
        if (self.Mode() != "edit") return false;

        if (field.Field() == "Title") return true;
        return false;
    };

    self.MediaUrl = ko.computed(function () {
        return self.__metadata.media_src;
    });

    self.MediaUrlW = ko.computed(function () {
        // http://spg-dev-jl/PublishingImages/_w/paste_634617554272984978_jpg.jpg

        var re = /(.*)\/([^\/]*)\.(.*)/gi;
        var m = re.exec(self.__metadata.media_src);
        if (m) {
            return m[1] + "/_w/" + m[2] + "_" + m[3] + ".jpg";
        }

        return self.__metadata.media_src;
    });

    self.ModifiedDate = ko.computed(function () {

        var m = rd.exec(self.Modified());
        if (m) {
            return eval("new " + m[0]);
        }
        return null;
    });

    self.ModifiedByPicture = ko.computed(function () {
        return "/_layouts/images/O14_person_placeHolder_96.png";
    });

    self.Refresh = function () {
        var ajaxurl = self.__metadata.uri;

        $.ajax({
            type: "GET",
            url: ajaxurl,
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            cache: false,
            processData: true,
            success: function (data, status, xhr) {

                if (status == "success" && data) {
                    ko.mapping.fromJS(data.d, listItemMapping, self)
                    ko.mapping.fromJS(
                        $.map(data.d, function (v, f) {

                            var t = typeof (v);
                            var m = rd.exec(v);
                            if (m) {
                                v = eval("new " + m[0]);
                                t = "date";
                            }
                            return { Field: f, Value: v, Type: t };
                        }),
                        {},
                        self.Fields);
                }
            },
            error: alert
        });

    };

    self.GetFieldValue = function (fieldname) {
        var i = self.Fields.mappedIndexOf({ "Field": fieldname });
        if (i == -1) return null;

        var f = self.Fields()[i];
        return f.Value();
    };

    self.Save = function () {

        var ajaxurl = self.__metadata.uri;

        $.ajax({
            type: "POST",
            url: ajaxurl,
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            beforeSend: function (xhr) {
                xhr.setRequestHeader("If-Match", self.__metadata.etag);
                //Using an HTTP MERGE so that the entire entity doesn't need to be sent to 
                //the server. 
                xhr.setRequestHeader("X-HTTP-Method", 'MERGE');
            },
            data: JSON.stringify({
                Title: self.GetFieldValue("Title")
            }),
            cache: false,
            processData: true,
            success: function (data, status, xhr) {

                if (status == "success") {
                    self.Refresh();
                    //$root.getTasks();	            	
                }
                self.Mode("");
            },
            error: function (xhr, status, statusText) {
                alert(xhr.responseText);
            }
        });

    };

    self.Delete = function () {
        if (window.confirm("Are you sure")) {
            alert("not implemented");
        }
    };

    self.ToggleExpand = function () {
        var expanded = ko.utils.unwrapObservable(self.Expanded);
        self.Expanded(!expanded);
    };



};



var vm = new WebViewModel();

function spa_ready() {
    ko.mapping.defaultOptions().copy = ["__metadata"];
    ko.applyBindings(vm);
    vm.GetLists();

    var $ = jQuery;

    /*!
    jQuery Wookmark plugin 0.5
    @name jquery.wookmark.js
    @author Christoph Ono (chri@sto.ph or @gbks)
    @version 0.5
    @date 3/19/2012
    @category jQuery plugin
    @copyright (c) 2009-2012 Christoph Ono (www.wookmark.com)
    @license Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
    */
    $.fn.wookmark = function (options) {

        if (!this.wookmarkOptions) {
            this.wookmarkOptions = $.extend({
                container: $('body'),
                offset: 2,
                autoResize: false,
                itemWidth: $(this[0]).outerWidth(),
                resizeDelay: 50
            }, options);
        } else if (options) {
            this.wookmarkOptions = $.extend(this.wookmarkOptions, options);
        }

        // Layout variables.
        if (!this.wookmarkColumns) {
            this.wookmarkColumns = null;
            this.wookmarkContainerWidth = null;
        }

        // Main layout function.
        this.wookmarkLayout = function () {
            // Calculate basic layout parameters.
            var columnWidth = this.wookmarkOptions.itemWidth + this.wookmarkOptions.offset;
            var containerWidth = this.wookmarkOptions.container.width();
            var columns = Math.floor((containerWidth + this.wookmarkOptions.offset) / columnWidth);
            var offset = Math.round((containerWidth - (columns * columnWidth - this.wookmarkOptions.offset)) / 2);

            offset = 0;

            // If container and column count hasn't changed, we can only update the columns.
            var bottom = 0;
            if (this.wookmarkColumns != null && this.wookmarkColumns.length == columns) {
                bottom = this.wookmarkLayoutColumns(columnWidth, offset);
            } else {
                bottom = this.wookmarkLayoutFull(columnWidth, columns, offset);
            }

            // Set container height to height of the grid.
            this.wookmarkOptions.container.css('height', bottom + 'px');
        };

        /**
        * Perform a full layout update.
        */
        this.wookmarkLayoutFull = function (columnWidth, columns, offset) {
            // Prepare Array to store height of columns.
            var heights = [];
            while (heights.length < columns) {
                heights.push(0);
            }

            // Store column data.
            this.wookmarkColumns = [];
            while (this.wookmarkColumns.length < columns) {
                this.wookmarkColumns.push([]);
            }

            // Loop over items.
            var item, top, left, i = 0, k = 0, length = this.length, shortest = null, shortestIndex = null, bottom = 0;
            for (; i < length; i++) {
                item = $(this[i]);

                // Find the shortest column.
                shortest = null;
                shortestIndex = 0;
                for (k = 0; k < columns; k++) {
                    if (shortest == null || heights[k] < shortest) {
                        shortest = heights[k];
                        shortestIndex = k;
                    }
                }

                // Postion the item.
                item.css({
                    position: 'absolute',
                    top: shortest + 'px',
                    left: (shortestIndex * columnWidth + offset) + 'px'
                });

                // Update column height.
                heights[shortestIndex] = shortest + item.outerHeight() + this.wookmarkOptions.offset;
                bottom = Math.max(bottom, heights[shortestIndex]);

                this.wookmarkColumns[shortestIndex].push(item);
            }

            return bottom;
        };

        /**
        * This layout function only updates the vertical position of the 
        * existing column assignments.
        */
        this.wookmarkLayoutColumns = function (columnWidth, offset) {
            var heights = [];
            while (heights.length < this.wookmarkColumns.length) {
                heights.push(0);
            }

            var i = 0, length = this.wookmarkColumns.length, column;
            var k = 0, kLength, item;
            var bottom = 0;
            for (; i < length; i++) {
                column = this.wookmarkColumns[i];
                kLength = column.length;
                for (k = 0; k < kLength; k++) {
                    item = column[k];
                    item.css({
                        left: (i * columnWidth + offset) + 'px',
                        top: heights[i] + 'px'
                    });
                    heights[i] += item.outerHeight() + this.wookmarkOptions.offset;

                    bottom = Math.max(bottom, heights[i]);
                }
            }

            return bottom;
        };

        // Listen to resize event if requested.
        this.wookmarkResizeTimer = null;
        if (!this.wookmarkResizeMethod) {
            this.wookmarkResizeMethod = null;
        }
        if (this.wookmarkOptions.autoResize) {
            // This timer ensures that layout is not continuously called as window is being dragged.
            this.wookmarkOnResize = function (event) {
                if (this.wookmarkResizeTimer) {
                    clearTimeout(this.wookmarkResizeTimer);
                }
                this.wookmarkResizeTimer = setTimeout($.proxy(this.wookmarkLayout, this), this.wookmarkOptions.resizeDelay)
            };

            // Bind event listener.
            if (!this.wookmarkResizeMethod) {
                this.wookmarkResizeMethod = $.proxy(this.wookmarkOnResize, this);
            }
            $(window).resize(this.wookmarkResizeMethod);
        };

        /**
        * Clear event listeners and time outs.
        */
        this.wookmarkClear = function () {
            if (this.wookmarkResizeTimer) {
                clearTimeout(this.wookmarkResizeTimer);
                this.wookmarkResizeTimer = null;
            }
            if (this.wookmarkResizeMethod) {
                $(window).unbind('resize', this.wookmarkResizeMethod);
            }
        };

        // Apply layout
        this.wookmarkLayout();

        // Display items (if hidden).
        this.show();
    };
}





SP.SOD.executeOrDelayUntilScriptLoaded(spa_ready, 'sp.js');
